#include "analog_clock.h"
#include <math.h>

// Font index helper for 5x8 font
static inline int fontIndex(char c) {
    if (c == ' ') return 0;
    if (c >= 'A' && c <= 'Z') return 1 + (c - 'A');
    if (c >= '0' && c <= '9') return 27 + (c - '0');
    if (c == '-') return 37;
    return 0;
}

void drawAnalogClock(Panel &panel, uint16_t posX, uint16_t posY, uint16_t w, uint16_t h, uint8_t hour, uint8_t minute, uint8_t second, const char* weekDayStr) {
    // compute center and radius inside bounding box
    uint16_t cx = posX + w / 2;
    uint16_t cy = posY + h / 2;
    uint16_t radius = (w < h ? w : h) / 2;
    if (radius > 2) radius -= 2; // small margin

    // clear the clock area
    if (w > 0 && h > 0) {
        panel.fillRect(posX, posY, posX + w - 1, posY + h - 1, 0, 0, 0);
    }

    // draw outer circle
    panel.drawCircle(cx, cy, radius, 255, 255, 0);

    // draw hour ticks
    for (int i = 0; i < 12; i++) {
        float angle = (i * 30.0f) * M_PI / 180.0f; // degrees to radians
        int16_t sx = cx + (int16_t)((radius - 4) * cos(angle));
        int16_t sy = cy + (int16_t)((radius - 4) * sin(angle));
        int16_t ex = cx + (int16_t)(radius * cos(angle));
        int16_t ey = cy + (int16_t)(radius * sin(angle));
        panel.drawLine(sx, sy, ex, ey, 255, 255, 0);
    }

    // Narrow 5x8 ASCII font (A-Z, 0-9, space, dash)
    static const uint8_t font5x8[][8] = {
        /* space */ {0,0,0,0,0,0,0,0},
        /* A */ {0x1E,0x05,0x05,0x1E,0x14,0x14,0x14,0x00},
        /* B */ {0x1F,0x15,0x15,0x1B,0x15,0x15,0x1F,0x00},
        /* C */ {0x1E,0x11,0x10,0x10,0x10,0x11,0x1E,0x00},
        /* D */ {0x1F,0x12,0x12,0x12,0x12,0x12,0x1F,0x00},
        /* E */ {0x1F,0x10,0x10,0x1E,0x10,0x10,0x1F,0x00},
        /* F */ {0x1F,0x10,0x10,0x1E,0x10,0x10,0x10,0x00},
        /* G */ {0x1E,0x10,0x10,0x17,0x11,0x11,0x1E,0x00},
        /* H */ {0x11,0x11,0x11,0x1F,0x11,0x11,0x11,0x00},
        /* I */ {0x1F,0x04,0x04,0x04,0x04,0x04,0x1F,0x00},
        /* J */ {0x1F,0x01,0x01,0x01,0x01,0x11,0x1E,0x00},
        /* K */ {0x11,0x12,0x14,0x18,0x14,0x12,0x11,0x00},
        /* L */ {0x10,0x10,0x10,0x10,0x10,0x10,0x1F,0x00},
        /* M */ {0x11,0x1B,0x15,0x15,0x11,0x11,0x11,0x00},
        /* N */ {0x11,0x19,0x15,0x13,0x11,0x11,0x11,0x00},
        /* O */ {0x0E,0x11,0x11,0x11,0x11,0x11,0x0E,0x00},
        /* P */ {0x1E,0x11,0x11,0x1E,0x10,0x10,0x10,0x00},
        /* Q */ {0x0E,0x11,0x11,0x11,0x15,0x12,0x0D,0x00},
        /* R */ {0x1E,0x11,0x11,0x1E,0x14,0x12,0x11,0x00},
        /* S */ {0x0F,0x10,0x10,0x0E,0x01,0x01,0x1E,0x00},
        /* T */ {0x1F,0x04,0x04,0x04,0x04,0x04,0x04,0x00},
        /* U */ {0x11,0x11,0x11,0x11,0x11,0x11,0x0E,0x00},
        /* V */ {0x11,0x11,0x11,0x11,0x11,0x0A,0x04,0x00},
        /* W */ {0x11,0x11,0x11,0x15,0x15,0x1B,0x11,0x00},
        /* X */ {0x11,0x11,0x0A,0x04,0x0A,0x11,0x11,0x00},
        /* Y */ {0x11,0x11,0x11,0x0E,0x04,0x04,0x04,0x00},
        /* Z */ {0x1F,0x01,0x02,0x04,0x08,0x10,0x1F,0x00},
        /* 0 */ {0x0E,0x11,0x13,0x15,0x19,0x11,0x0E,0x00},
        /* 1 */ {0x04,0x0C,0x04,0x04,0x04,0x04,0x0E,0x00},
        /* 2 */ {0x0E,0x11,0x01,0x02,0x04,0x08,0x1F,0x00},
        /* 3 */ {0x1F,0x02,0x04,0x02,0x01,0x11,0x0E,0x00},
        /* 4 */ {0x02,0x06,0x0A,0x12,0x1F,0x02,0x02,0x00},
        /* 5 */ {0x1F,0x10,0x1E,0x01,0x01,0x11,0x0E,0x00},
        /* 6 */ {0x06,0x08,0x10,0x1E,0x11,0x11,0x0E,0x00},
        /* 7 */ {0x1F,0x01,0x02,0x04,0x08,0x08,0x08,0x00},
        /* 8 */ {0x0E,0x11,0x11,0x0E,0x11,0x11,0x0E,0x00},
        /* 9 */ {0x0E,0x11,0x11,0x0F,0x01,0x02,0x0C,0x00},
        /* - */ {0x00,0x00,0x00,0x1F,0x00,0x00,0x00,0x00},
    };

    // Draw week day string at the midpoint between 12 o'clock and the center, using a narrow 5x8 font
    if (weekDayStr) {
        uint8_t textLen = 0;
        for (const char* p = weekDayStr; *p; ++p) ++textLen;
        uint8_t charSpacing = 1;
        uint8_t textWidth = (5 + charSpacing) * textLen - charSpacing;
        uint8_t textHeight = 8;
        int16_t midY = (cy - radius + cy) / 2;
        int16_t textX = cx - textWidth / 2;
        int16_t textY = midY - textHeight / 2;
        for (uint8_t i = 0; i < textLen; ++i) {
            int idx = fontIndex(weekDayStr[i]);
            for (uint8_t row = 0; row < 8; ++row) {
                uint8_t bits = font5x8[idx][row];
                for (uint8_t col = 0; col < 5; ++col) {
                    if (bits & (1 << (4 - col))) {
                        panel.drawPixel(textX + i * (5 + charSpacing) + col, textY + row, 0, 255, 0);
                    }
                }
            }
        }
    }

    // Draw date string below the center, between center and 6 o'clock
    char dateStr[8] = "2025-09";
    {
        time_t now = time(nullptr);
        struct tm timeinfo;
        if (localtime_r(&now, &timeinfo)) {
            snprintf(dateStr, sizeof(dateStr), "%04d-%02d", 1900 + timeinfo.tm_year, 1 + timeinfo.tm_mon);
        }
    }
    uint8_t dateLen = 0;
    for (const char* p = dateStr; *p; ++p) ++dateLen;
    uint8_t charSpacing = 1;
    uint8_t dateWidth = (5 + charSpacing) * dateLen - charSpacing;
    uint8_t dateHeight = 8;
    int16_t midY2 = (cy + (cy + radius)) / 2;
    int16_t dateX = cx - dateWidth / 2;
    int16_t dateY = midY2 - dateHeight / 2;
    for (uint8_t i = 0; i < dateLen; ++i) {
        int idx = fontIndex(dateStr[i]);
        for (uint8_t row = 0; row < 8; ++row) {
            uint8_t bits = font5x8[idx][row];
            for (uint8_t col = 0; col < 5; ++col) {
                if (bits & (1 << (4 - col))) {
                    panel.drawPixel(dateX + i * (5 + charSpacing) + col, dateY + row, 0, 255, 0);
                }
            }
        }
    }

    // Draw AM/PM at the midpoint between center and 3 o'clock
    const char* ampmStr = (hour < 12) ? "AM" : "PM";
    uint8_t ampmLen = 0;
    for (const char* p = ampmStr; *p; ++p) ++ampmLen;
    uint8_t ampmCharSpacing = 1;
    uint8_t ampmWidth = (5 + ampmCharSpacing) * ampmLen - ampmCharSpacing;
    uint8_t ampmHeight = 8;
    int16_t midX = (cx + (cx + radius)) / 2;
    int16_t ampmX = midX - ampmWidth / 2;
    int16_t ampmY = cy - ampmHeight / 2;
    for (uint8_t i = 0; i < ampmLen; ++i) {
        int idx = fontIndex(ampmStr[i]);
        for (uint8_t row = 0; row < 8; ++row) {
            uint8_t bits = font5x8[idx][row];
            for (uint8_t col = 0; col < 5; ++col) {
                if (bits & (1 << (4 - col))) {
                    panel.drawPixel(ampmX + i * (5 + ampmCharSpacing) + col, ampmY + row, 0, 255, 0);
                }
            }
        }
    }

    // compute angles for hands (0 at 12 o'clock, increasing clockwise)
    float hourAngle = ((hour % 12) + minute / 60.0f) * 30.0f * M_PI / 180.0f;
    float minuteAngle = minute * 6.0f * M_PI / 180.0f;
    float secondAngle = second * 6.0f * M_PI / 180.0f;

    // draw hour hand
    int16_t hx = cx + (int16_t)((radius * 0.5f) * sin(hourAngle));
    int16_t hy = cy - (int16_t)((radius * 0.5f) * cos(hourAngle));
    panel.drawLine(cx, cy, hx, hy, 255, 0, 0);

    // draw minute hand (now yellow)
    int16_t mx = cx + (int16_t)((radius * 0.7f) * sin(minuteAngle));
    int16_t my = cy - (int16_t)((radius * 0.7f) * cos(minuteAngle));
    panel.drawLine(cx, cy, mx, my, 255, 255, 0);

    // draw second hand (blue), 4 pixels below hour hand end
    int16_t sx = cx + (int16_t)((radius * 0.9f) * sin(secondAngle));
    int16_t sy = cy - (int16_t)((radius * 0.9f) * cos(secondAngle)) + 4;
    panel.drawLine(cx, cy, sx, sy, 0, 0, 255);

    // Draw day of month (D) at the midpoint between center and 9 o'clock, using a 1.5x scaled 5x8 font, white color
    int day = 1;
    {
        time_t now = time(nullptr);
        struct tm timeinfo;
        if (localtime_r(&now, &timeinfo)) {
            day = timeinfo.tm_mday;
        }
    }
    // Only show one digit if day < 10
    char dayStr[3];
    if (day < 10) {
        snprintf(dayStr, sizeof(dayStr), "%d", day);
    } else {
        snprintf(dayStr, sizeof(dayStr), "%02d", day);
    }
    uint8_t numDigits = (day < 10) ? 1 : 2;
    // Use the same 5x8 font as other text
    // Midpoint between center and 9 o'clock
    int16_t midX_day = (cx + (cx - radius)) / 2;
    float scale = 1.5f;
    uint8_t charW = 5 * scale;
    uint8_t charH = 8 * scale;
    // Increase spacing between digits
    uint8_t charSpacingDay = 3 * scale; // slightly larger spacing
    uint8_t dayWidth = (charW + charSpacingDay) * numDigits - charSpacingDay;
    int16_t dayX = midX_day - dayWidth / 2;
    // Align vertical center of date with vertical center of panel
    int16_t dayY = cy - charH / 2;
    for (uint8_t i = 0; i < numDigits; ++i) {
        int idx = fontIndex(dayStr[i]);
        for (uint8_t row = 0; row < 8; ++row) {
            uint8_t bits = font5x8[idx][row];
            for (uint8_t col = 0; col < 5; ++col) {
                if (bits & (1 << (4 - col))) {
                    // 1.5x scale: draw 3x2 block for each pixel
                    int px = dayX + i * (charW + charSpacingDay) + col * scale;
                    int py = dayY + row * scale;
                    // Draw 3x2 block (approximate 1.5x)
                    panel.drawPixel(px, py, 0, 255, 0);
                    panel.drawPixel(px+1, py, 0, 255, 0);
                    panel.drawPixel(px+2, py, 0, 255, 0);
                    panel.drawPixel(px, py+1, 0, 255, 0);
                    panel.drawPixel(px+1, py+1, 0, 255, 0);
                    panel.drawPixel(px+2, py+1, 0, 255, 0);
                }
            }
        }
    }
}
